﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using CID.Execution.Support.Information;
using CID.Execution.Support.TemplateHandling;

namespace CID.Execution.Agent.TemplateHandling
{
    public class BATTemplateHandler : TemplateHandlerBase
    {
        private const string StandardErrorFile = "StandardError.txt";
        private const string StandardOutputFile = "StandardOutput.txt";

        private string workingPath;
        private string batchFilePath;
        private string standardOutputPath;
        private string standardErrorPath;
        /*
        public void ExecuteTemplate(TemplateInfo template, IEnumerable<ParameterValueInfo> parameterValues, IEnumerable<ParameterValueInfo> additionalParameterValues, IEnumerable<ServerInfo> targetServers)
        {
            var workingPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
            var batchFilePath = Path.Combine(workingPath, Path.ChangeExtension(Path.GetRandomFileName(), ".bat"));
            var standardOutputPath = Path.Combine(workingPath, StandardOutputFile);
            var standardErrorPath = Path.Combine(workingPath, StandardErrorFile);
            StreamReader standardError = null;
            StreamReader standardOutput = null;

            try
            {
                Directory.CreateDirectory(workingPath);
                new BATTemplateFileWriter(template.Content, parameterValues.Concat(additionalParameterValues)).WriteTo(batchFilePath);

                //It is necessary to use the Shell Execute to have full support for commands like xcopy
                //Standard Output and Error are redirected to files in order to be able to read them later and use their content for messages
                var processStartInfo = new ProcessStartInfo("cmd.exe", String.Format("/C \"{0}\" 1>{1} 2>{2}", batchFilePath, StandardOutputFile, StandardErrorFile));
                processStartInfo.CreateNoWindow = true;
                processStartInfo.WorkingDirectory = workingPath;
                var process = Process.Start(processStartInfo);
                process.WaitForExit();

                standardOutput = new StreamReader(standardOutputPath);
                standardError = new StreamReader(standardErrorPath);

                if ((process.ExitCode != 0) || !standardError.EndOfStream)
                {
                    throw new ApplicationException(String.Format("The BAT Template execution failed.\r\nExit Code: {0}\r\n\r\n\r\n\r\nError:\r\n\r\n{1}\r\n\r\n\r\nOutput:\r\n\r\n{2}",
                        process.ExitCode, standardError.ReadToEnd(), standardOutput.ReadToEnd()));
                }
            }
            catch (Exception ex)
            {
                throw new TemplateHandlingException(ex);
            }
            finally
            {
                if (standardOutput != null) standardOutput.Dispose();
                if (standardError != null) standardError.Dispose();
                if (File.Exists(batchFilePath)) File.Delete(batchFilePath);
                if (Directory.Exists(workingPath)) Directory.Delete(workingPath, true);
            }
        }
        */

        protected override void PrepareTemplate(TemplateInfo template, IEnumerable<ParameterValueInfo> parameterValues, System.Text.StringBuilder detailsBuilder)
        {
            workingPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
            batchFilePath = Path.Combine(workingPath, Path.ChangeExtension(Path.GetRandomFileName(), ".bat"));
            standardOutputPath = Path.Combine(workingPath, StandardOutputFile);
            standardErrorPath = Path.Combine(workingPath, StandardErrorFile);
            
            Directory.CreateDirectory(workingPath);
            new BATTemplateFileWriter(template.Content, parameterValues).WriteTo(batchFilePath);
        }

        protected override void ExecuteTemplate(TemplateInfo template, IEnumerable<ParameterValueInfo> parameterValues, StringBuilder detailsBuilder)
        {
            StreamReader standardError = null;
            StreamReader standardOutput = null;
            try
            {
                //It is necessary to use the Shell Execute to have full support for commands like xcopy
                //Standard Output and Error are redirected to files in order to be able to read them later and use their content for messages
                var processStartInfo = new ProcessStartInfo("cmd.exe", String.Format("/C \"{0}\" 1>{1} 2>{2}", batchFilePath, StandardOutputFile, StandardErrorFile));
                processStartInfo.CreateNoWindow = true;
                processStartInfo.WorkingDirectory = workingPath;
                var process = Process.Start(processStartInfo);
                process.WaitForExit();

                standardOutput = new StreamReader(standardOutputPath);
                standardError = new StreamReader(standardErrorPath);

                if ((process.ExitCode != 0) || !standardError.EndOfStream)
                {
                    throw new ApplicationException(String.Format("The BAT Template execution failed.\r\nExit Code: {0}\r\n\r\n\r\n\r\nError:\r\n\r\n{1}\r\n\r\n\r\nOutput:\r\n\r\n{2}",
                        process.ExitCode, standardError.ReadToEnd(), standardOutput.ReadToEnd()));
                }
                detailsBuilder.AppendLine().AppendLine("BAT Execution ended").AppendLine("Output:").AppendLine(standardOutput.ReadToEnd()).AppendLine().AppendLine();
            }
            catch (Exception ex)
            {
                throw new TemplateHandlingException(ex);
            }
            finally
            {
                if (standardOutput != null) standardOutput.Dispose();
                if (standardError != null) standardError.Dispose();
            }
        }

        protected override void ReleaseTemplate(TemplateInfo template, StringBuilder detailsBuilder)
        {
            if (File.Exists(batchFilePath)) File.Delete(batchFilePath);
            if (Directory.Exists(workingPath)) Directory.Delete(workingPath, true);
        }
    }
}
